/*
 * Copyright (c) 2010-2011, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "alkes/effector/FormatConverter.h"
#include "alkes/media/LockImageBuffer.h"

namespace alkes {

FormatConverter* FormatConverter::create(ImageBufferFactory* factory, PixelFormat format)
{
    if (!factory)
        return 0;

    const PixelFormatTraits* traits = alkes_get_pixel_format_traits(format);
    if (!traits)
        return 0;

    return new FormatConverter(factory, format, traits);
}

void FormatConverter::destroy()
{
    delete this;
}

FormatConverter::FormatConverter(ImageBufferFactory* factory, PixelFormat format, const PixelFormatTraits* traits)
: ImageFilter(factory)
, format_(format)
, traits_(traits)
{
}

FormatConverter::~FormatConverter()
{
}

bool FormatConverter::onApply(ImageBuffer* src, intrusive_ptr<ImageBuffer>* dst)
{
    intrusive_ptr<ImageBuffer> temp(0);

    PixelFormat src_format = src->getPixelFormat();
    if (src_format == format_)
    {
        temp = cloneImageBuffer(src);

        if (temp)
            *dst = static_cast<ImageBuffer*>(temp);

        return 0 != temp;
    }

    const PixelFormatTraits* src_traits = alkes_get_pixel_format_traits(src_format);
    if (!src_traits)
        return false;

    uint16_t width, height;
    src->getImageSize(width, height);
    temp = createImageBuffer(width, height, format_);
    if (!temp)
        return false;

    LockImageBufferRead read_lock(src);
    if (!read_lock)
        return false;

    LockImageBufferWrite write_lock(temp);
    if (!write_lock)
        return false;

    const uint8_t* src_p = read_lock;
    const uint8_t* sp;
    int32_t src_pitch = read_lock.getPitch();
    uint8_t* dst_p = write_lock;
    uint8_t* dp;
    int32_t dst_pitch = write_lock.getPitch();
    Color c;
    uint16_t x, y;
    for (y = 0; y < height; ++y, src_p += src_pitch, dst_p += dst_pitch)
    {
        sp = src_p;
        dp = dst_p;
        for (x = 0; x < width; ++x, sp += src_traits->bytes, dp += traits_->bytes)
        {
            c = src_traits->getPixel(sp);
            traits_->setPixel(dp, c);
        }
    }

    write_lock.detach();
    read_lock.detach();

    *dst = static_cast<ImageBuffer*>(temp);

    return true;
}

}
